﻿using System;
using System.Text;
using System.Windows.Forms;
using Microsoft.Office.Tools.Ribbon;
using SRS;
using SRS.Encryption;
using Word = Microsoft.Office.Interop.Word;

namespace TesWordAddIn
{
    public partial class SRS_Ribbon
    {
        private Word.Document doc;
        public Word.Document Doc
        {
            get { return doc; }
            set { doc = value; }
        }

        private void SRS_Ribbon_Load(object sender, RibbonUIEventArgs e)
        {

        }

        #region Event Click
        private void Dekripsi_Button_Click(object sender, RibbonControlEventArgs e)
        {
            if (Validate())
            {
                Decrypt();
            }
        }

        private void Enkripsi_Button_Click(object sender, RibbonControlEventArgs e)
        {
            if (Validate())
            {
                Encrypt();
            }
        }
        #endregion

        #region Validator
        private bool Validate()
        {
            if (textBoxKey.Text.Length < 1)
            {
                ShowError("Kunci harus diisi.");
                return false;
            }

            if (GetDocText().Length < 1)
            {
                ShowError("Document harus diisi.");
                return false;
            }

            return true;
        }
        #endregion

        #region Encryption
        #region Encrypt
        private void Encrypt()
        {
            byte[] body;
            SRSEncryption srs = GetEncryptionAlgorithm(comboBoxEncryptionMode.SelectedItemIndex);

            byte[] keyBytes = GetKey();
            byte[] plainBytes = StringToArrayByte(GetDocText());
            int unitLength = 1;

            // Header
            byte[] header = EncryptHeader(keyBytes, plainBytes.Length, unitLength, comboBoxEncryptionMode.SelectedItemIndex);

            // Body
            body = srs.Encrypt(keyBytes, plainBytes, unitLength);

            byte[] concat = Helper.Concat(header, body);

            SetDocText(PrintBytes(concat));
        }
        
        private byte[] EncryptHeader(byte[] keyBytes, int plainLength, int unitLength, int mode)
        {
            int keyLength = keyBytes.Length;
            byte[] header = new byte[keyLength];

            // Mode
            header[0] = (byte)mode;

            // Block Length
            header[1] = (byte)keyLength;

            // Unit Length
            header[2] = (byte)unitLength;

            // Padding
            if (mode == 0 || mode == 1)
            {
                header[3] = (byte)((keyLength - (plainLength % keyLength)) % keyLength);
            }
            else
            {
                header[3] = (byte)((unitLength - (plainLength % unitLength)) % unitLength);
            }

            SRSEncryption srs = new SRSEncryption();
            return srs.EncryptBlock(keyBytes, header);
        }
        #endregion

        #region Decrypt
        private void Decrypt()
        {
            // Get key and Cipher
            byte[] keyBytes = GetKey();
            int keyLength = keyBytes.Length;
            byte[] cipherBytes = ParseCipher();
            int cipherLength = cipherBytes.Length;

            // Validate key length
            if (keyLength > cipherLength - 1)
            {
                ShowError("Dekripsi Error. Kunci terlalu panjang.");
                return;
            }

            // Get Header
            byte[] header = new byte[keyLength];
            Array.Copy(cipherBytes, 0, header, 0, keyLength);

            // Get Body
            byte[] body = new byte[cipherLength - keyLength];
            Array.Copy(cipherBytes, keyLength, body, 0, cipherLength - keyLength);

            // Decrypt Header
            header = DecryptHeader(header, keyBytes);
            int mode = header[0];
            int unitLength = header[2];
            int padding = header[3];

            // Validation unitLength
            if (unitLength > keyLength)
            {
                unitLength = keyLength;
            }

            // Decrypt Body
            SRSEncryption srs = GetEncryptionAlgorithm(mode);
            body = srs.Decrypt(keyBytes, body, unitLength);

            int newBodyLength = body.Length - padding;

            // Validation newBodyLength
            if (newBodyLength < 1)
            {
                newBodyLength = body.Length;
            }

            // Set to editor
            byte[] newBody = new byte[newBodyLength];
            Array.Copy(body, 0, newBody, 0, newBodyLength);

            SetDocText(ArrayByteToString(newBody));
        }

        private byte[] DecryptHeader(byte[] header, byte[] keyBytes)
        {
            SRSEncryption srs = new SRSEncryption();

            return srs.DecryptBlock(keyBytes, header);
        }
        #endregion
        #endregion

        #region Helper
        private static String PrintBytes(byte[] bytes)
        {
            int length = bytes.Length;
            StringBuilder sb = new StringBuilder();
            int i;
            for (i = 0; i < length - 1; ++i)
            {
                sb.Append(bytes[i]);
                sb.Append(" ");
            }
            sb.Append(bytes[i]);

            return sb.ToString();
        }

        private byte[] StringToArrayByte(string p)
        {
            return Helper.StringToArrayByte(p);
        }

        private string ArrayByteToString(byte[] concat)
        {
            return Helper.ArrayByteToString(concat);
        }

        private void SetDocText(String s)
        {
            Doc.Content.Text = s;
        }

        private string GetDocText()
        {

            return Doc.Content.Text.Substring(0, Doc.Content.Text.Length - 1);
        }

        private byte[] ParseCipher()
        {
            String s = GetDocText();
            String[] ss = s.Split(' ');
            byte[] bytes = new byte[ss.Length];

            for (int i = 0; i < bytes.Length; ++i)
            {
                int temp = 0;
                Int32.TryParse(ss[i], out temp);
                bytes[i] = (byte)temp;
            }
            return bytes;
        }

        private byte[] GetKey()
        {
            byte[] keyBytes = StringToArrayByte(textBoxKey.Text);
            int keyLength = keyBytes.Length;

            if (keyLength < 8)
            {
                // Do Padding
                byte[] newKeyBytes = new byte[8];
                Array.Copy(keyBytes, 0, newKeyBytes, 0, keyLength);

                for (int i = keyLength; i < 8; ++i)
                {
                    newKeyBytes[i] = 100;
                }

                return newKeyBytes;
            }

            return keyBytes;
        }

        private SRSEncryption GetEncryptionAlgorithm(int mode)
        {
            SRSEncryption srs = new ECB();

            if (mode == 0)
            {
                srs = new ECB();
            }
            else if (mode == 1)
            {
                srs = new CBC();
            }
            else if (mode == 2)
            {
                srs = new CFB();
            }
            else if (mode == 3)
            {
                srs = new OFB();
            }
            return srs;
        }
        
        private void ShowError(string p)
        {
            MessageBox.Show(p, "Form Validation");
        }
        #endregion
    }
}
